home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / pctjag86.arc / SPRITES2.ASM < prev    next >
Assembly Source File  |  1986-05-27  |  21KB  |  615 lines

  1. ;
  2. ; *** Listing 2 ***
  3. ;
  4. ;These routines produce the effect of hardware sprites in software
  5. ; on IBM PC compatible computers. They put objects onto the screen
  6. ; in a manner which preserves the background, and produces no
  7. ; undesirable fringe or overlap effects. Operations which affect
  8. ; video buffer memory are performed as much as possible during
  9. ; video non-display periods to avoid other undesirable effects.
  10. ;
  11. ; Entry points and parameters:
  12. ;
  13. ;   Initialize - Sets the background buffer address to be used to erase
  14. ;    objects, resets internal flags and queue, and on EGAs
  15. ;    sets up the use of the vertical interrupt to drive the
  16. ;    drawing routines.
  17. ;
  18. ;    Inputs    - AX holds paragraph address of background buffer.
  19. ;    Outputs - None.
  20. ;
  21. ;   Terminate  - Resets the EGA vertical interrupt hardware and vector
  22. ;
  23. ;    Inputs    - None.
  24. ;    Outputs - None.
  25. ;
  26. ;   Object_services - Sets X,Y and Form address for a given object
  27. ;    to be drawn, and activates or deactivates the object.
  28. ;
  29. ;    Inputs    - CX holds X position in bytes (0-79) of upper
  30. ;           left hand corner of object. 0 is leftmost.
  31. ;        - BX holds Y position in lines (0-198) 0 is top.
  32. ;           BX must be even! Objects cannot start on odd lines.
  33. ;           Objects must also be an even number of lines high.
  34. ;        - DI holds object number. Higher numbered objects
  35. ;           will appear to be in front of lower numbered
  36. ;           objects when they overlap.
  37. ;        - SI holds the offset in the code segment of the form
  38. ;           to be drawn for the object. A value of 0ffffh means
  39. ;           that the object is to be erased, then ignored.
  40. ;           Forms must be in the following format:
  41. ;
  42. ;              byte 0 - height in lines (h)
  43. ;              byte 1 - width in bytes  (w)
  44. ;              followed by w X h (mask word, image word) pairs.
  45. ;
  46. ;    Outputs - None.
  47. ;
  48. ;    Registers - All are saved, except flags
  49. ;
  50. ;    Warning - No bounds checking is done. X,Y or object numbers
  51. ;           out of range can send your program into hyperspace.
  52. ;
  53. ;   Put_objects_on_screen - This routine should be called by a program
  54. ;    running on a CGA to put the objects on the screen. It must be
  55. ;    far-called as if it were an interrupt routine. For example:
  56. ;
  57. ;               pushf
  58. ;               call far ptr put_objects_on_screen
  59. ;
  60. ;    For best results this routine should be called immediately
  61. ;     upon the sensing of vertical retrace.
  62. ;
  63. ;    Inputs    - None.
  64. ;    Outputs - None.
  65. ;
  66. ; Vert_int_modulo_count - This memory word is incremented each time
  67. ;   the objects are put into the screen map. On EGAs it can be used
  68. ;   to synchronize a program to the constant time base provided by
  69. ;   the vertical interrupt.
  70. ;
  71. ;The flag below must be set properly before assembling this program
  72. ;
  73. ega    equ  0         ;1 to assemble for Enhanced Graphics Adapter
  74.              ;0 to assemble for Color Graphics Adapter
  75. cga    equ  (ega xor 1) ;the opposite status of ega
  76. ;
  77. bios_data_segment segment at 40h    ;BIOS keeps its data at 400h;
  78.     org    63h            ;at 463h is a word that holds
  79. bios_crtc_base_address    dw    ?    ; the CRT controller's base
  80. bios_data_segment ends            ; address
  81. ;
  82. ;
  83. cseg    segment para public 'cseg'
  84.     assume    cs:cseg,ds:cseg,es:nothing
  85.     public    initialize,terminate,object_services
  86.     public    put_objects_on_screen,vert_int_modulo_count
  87. ;
  88. ;Memory for the parameters used to keep track of objects is reserved
  89. ; below. Many of the parameters stored are very code specific so that
  90. ; the size and number of objects which could be processed during
  91. ; vertical non-display time could be maximized.
  92. ;
  93. number_of_objects equ    3  ;this should be set to the maximum number
  94.                ; of objects or priorities which will
  95.                ; need to be kept track of at one time.
  96. ;
  97. queue label word
  98. ;
  99. draw_screen_offset    dw ?  ;offset in screen memory buffer of upper
  100.                   ; left hand corner of object. 0ffffh if
  101.                   ; object is to be ignored.
  102. dist_to_odd_scan_line    dw ?  ;distance from end of object on an even
  103.                   ; scan line to the start of the object
  104.                   ; on the next (odd) scan line
  105. dist_to_even_scan_line    dw ?  ;distance from end of object on an odd
  106.                   ; scan line to the start of the object
  107.                   ; on the next (even) scan line
  108. ;
  109. erase_parms label word
  110. ;
  111. erase_width         dw ?  ;the object's screen image width in words
  112. erase_entry_point    dw ?  ;the address of the inline code to do erase
  113. erase_screen_offset  dw ?  ;the address where object was last drawn
  114.                ; 0ffffh if object is not to be erased.
  115. erase_image_offset   dw ?  ;used to determine if need to erase when
  116.                ; object is in old position
  117. ;
  118. length_of_erase_parms equ $-erase_parms
  119. ;
  120. draw_col_entry_point dw ?  ;address of the column code for drawing
  121. draw_row_entry_point dw ?  ;address of the row inline code for drawing
  122. draw_image_offset    dw ?  ;offset in the code segment of the image
  123. ;
  124. queue_item_length equ ($ - queue) ;number of bytes for each item
  125. distance_from_entry_point_to_next_item equ $ - erase_entry_point
  126. distance_from_image_to_next_item equ $ - draw_image_offset
  127. ;
  128.     db    (  (number_of_objects-1) * queue_item_length ) dup(?)
  129. end_of_queue label word
  130. ;
  131. vert_int_modulo_count    dw 0  ;incremented each time a vertical
  132.                   ; interrupt occurs
  133. background_segment    dw ?  ;place to hold the paragraph address
  134.                   ; of the background buffer used to
  135.                   ; erase objects
  136. crtc_base_address    dw ?  ;will hold register address
  137. ;
  138. old_int10_offset    dw ?  ;place to store the vector contents
  139. old_int10_segment    dw ?  ; so they can be restored when finished
  140. ;
  141. old_int_mask        db ?  ;place to store the mask register's
  142.                   ; contents so it can be restored
  143. ;
  144. true    equ    1  ;used for flag values
  145. false    equ    0  ;
  146. ;
  147. need_to_draw_something_flag db false ;true if a change needs to be
  148.                      ; made to any of the objects'
  149.                      ; screen images
  150. ;
  151. screen_buffer_paragraph_adr equ 0b800h
  152. ;
  153. ;
  154. initialize proc near
  155.     cld                   ;count up
  156.     push    ds               ;
  157.     mov    cs:[background_segment],ax ;store background adr
  158.     mov    ax,cs               ;make data segment
  159.     mov    ds,ax               ; same as code segment
  160.                        ; since that is where data
  161.     mov    es,ax               ; used by this routine is
  162.     mov    di,offset queue        ;turn off all objects
  163.     mov    cx,(number_of_objects * queue_item_length)/2
  164.     mov    ax,0ffffh           ;
  165.     rep stosw               ;
  166. ;
  167.     mov    [need_to_draw_something_flag],false ;nothing to draw
  168. if ega
  169.     sub    ax,ax                ;swapping interrupt
  170.     mov    ds,ax                ; vectors with our
  171.     mov    bx,(10*4)            ; interrupt handler
  172.     mov    ax,offset put_objects_on_screen ;our vertical int
  173.     mov    dx,cs                ; handler address
  174.     cli                    ;disable interrupts
  175.     xchg    [bx],ax             ;offset
  176.     xchg    [bx+2],dx            ;segment
  177.     mov    cs:[old_int10_offset],ax    ;save old value so we
  178.     mov    cs:[old_int10_segment],dx    ; can restore it upon
  179. ;                        ; termination
  180.     mov    ax,bios_data_segment        ;find the register
  181.     mov    ds,ax                ; address
  182.     assume    ds:bios_data_segment        ;
  183.     mov    dx,[bios_crtc_base_address]    ;
  184.     mov    cs:[crtc_base_address],dx    ;save it in code seg
  185.     mov    al,11h                ;select vertical
  186.     out    dx,al                ; retrace end register
  187.     mov    al,04h                ; and flip it off
  188.     inc    dx                ;
  189.     out    dx,al                ;
  190.     mov    al,14h                ; then flip it on
  191.     out    dx,al                ;
  192. ;
  193.     in    al,21h                ;enable IRQ2
  194.     mov    cs:[old_int_mask],al        ; save old value
  195.     and    al,not 4            ;
  196.     out    21h,al                ;
  197. ;
  198.     sti                    ;enable interrupts
  199. endif
  200.     pop    ds                ;restore data segment
  201.     ret
  202. initialize endp
  203. ;
  204. terminate    proc    near   ;only needs to be used when assembled
  205. if ega                   ; for use on an EGA
  206.     mov    dx,[crtc_base_address]
  207.     mov    al,11h
  208.     out    dx,al
  209.     inc    dx
  210.     mov    al,24h           ;bit 5 high to disable, bit 4 low to
  211.     out    dx,al           ; clear vertical interrupt
  212.     push    ds
  213.     sub    ax,ax              ;restore original interrupt
  214.     mov    ds,ax              ; 10 vector
  215.     mov    bx,(10*4)          ;
  216.     mov    ax,cs:[old_int10_offset]  ;
  217.     mov    dx,cs:[old_int10_segment] ;
  218.     cli                  ;make sure interrupt
  219.     mov    [bx],ax           ; doesn't occur while
  220.     mov    [bx+2],dx          ; there is an inconsistant
  221.                       ; vector/mask
  222.     mov    bl,cs:[old_int_mask]      ;restore IRQ2 mask bit
  223.     and    bl,4              ; to state it had when
  224.     in    al,21h              ; Initialize was called
  225.     and    al,not 4          ;
  226.     or    al,bl              ;
  227.     out    21h,al              ;
  228.     sti
  229.     pop    ds
  230. endif
  231.     ret
  232. terminate endp
  233. ;
  234. object_services proc near
  235.     cld            ;
  236.     push    es        ;save the registers used
  237.     push    ds        ;
  238.     push    ax        ;
  239.     push    bx        ;
  240.     push    cx        ;
  241.     push    si        ;
  242.     push    di        ;
  243. ;
  244.     mov    ax,cs        ;everything will be in code segment
  245.     mov    es,ax        ;
  246.     mov    ds,ax        ;
  247.  
  248. ;
  249.     shl    di,1        ;multiply object number
  250.     shl    di,1        ; which is in DI by 20 to
  251.     mov    ax,di        ; find object's parameter table
  252.     shl    di,1        ; offset in queue structure
  253.     shl    di,1        ; (NOTE: If a code change alter
  254.     add    di,ax        ;  queue_item_length this code must
  255. ;                ;  be changed!)
  256.     mov    ax,offset queue ;point directly to object's first
  257.     add    di,ax        ; parameter
  258.     mov    ax,[bx+even_line_screen_offset_table]
  259.     add    ax,cx        ;find screen offset of top left corner
  260. if ega
  261.     cli     ;can't allow parameters to be just half
  262.          ; changed if a vertical interrupt occurs
  263. endif
  264.     cmp    si,0ffffh    ;if object is to be turned off then
  265.     jne    save_position    ; need to store a 0ffffh for the draw
  266.     mov    ax,si        ; screen position
  267.     stosw            ;
  268.     jmp short finish_services
  269. save_position:            ;
  270.     stosw         ;save as first parameter (draw_screen_offset)
  271.     lodsb         ;get the height of the image
  272.     xor    ah,ah     ;make height a word
  273.     mov    bx,ax     ;store height
  274.     lodsb         ;get the width of the image in bytes
  275.     mov    cx,2000h ;calculate amount to add after even scan
  276.     sub    cx,ax     ; lines are drawn to get the address of the
  277.     xchg    ax,cx     ; next scan line, and store it in queue
  278.     stosw         ;
  279.     mov    ax,1fb0h ;calculate amount to subtract after odd scan
  280.     add    ax,cx     ; lines are drawn to get the address of the
  281.     stosw         ; next scan line, and store it in queue
  282.     mov    ax,cx     ;store the width in queue
  283.     shr    ax,1     ; width is stored as number of words
  284.     stosw         ;
  285.     mov    ax,[bx+erase_inline_vector_table-2]
  286.              ;-2 because there is no 0 lines entry point
  287.     stosw         ;store the place to jump to erase an image
  288.              ; of this height
  289.     add    di,4     ;skip erase_screen_offset and
  290.              ; erase_image_offset as these are filled
  291.              ; in when an object is drawn
  292.     xchg    si,cx     ;swap image offset with width
  293.     mov    ax,[si+column_inline_vector_table-2] ;inline code adr
  294.     stosw         ; driver operates with words, so there is no
  295.              ; need to divide SI by two to do table lookup
  296.     mov    ax,[bx+row_inline_vector_table-2] ;inline code adr
  297.     stosw         ; which calls column inline code for each row
  298.     mov    [di],cx  ;last param to put on queue is image offset
  299. ;
  300. finish_services:
  301.     mov    [need_to_draw_something_flag],true ;record change
  302. if ega
  303.     sti         ;all parameters have been put on queue
  304.              ; so interrupts are safe now
  305. endif
  306.     pop    di     ;restore those registers that were used
  307.     pop    si     ;
  308.     pop    cx     ;
  309.     pop    bx     ;
  310.     pop    ax     ;
  311.     pop    ds     ;
  312.     pop    es     ;
  313.     ret         ;
  314. object_services endp
  315. ;
  316. ;This table is used to find the offset of an even scan line in the
  317. ; memory map of the color graphics adapter in medium resolution mode.
  318. ;
  319. even_line_screen_offset_table label word
  320. xx=0
  321.     rept    100    ;there are 100 even lines
  322.     dw    xx*50h    ; each is 50h (80 decimal) long
  323. xx=xx+1
  324.     endm
  325. ;
  326. use_old_vector:
  327.     pop    ax    ;restore registers used before
  328.     pop    dx    ; jumping to previous IRQ2 handler
  329.     jmp dword ptr cs:[old_int10_offset]
  330. ;
  331. put_objects_on_screen proc far
  332.     push    dx    ;save registers used by EGA code
  333.     push    ax    ;
  334. if ega
  335.             ;must check if interrupt is being signaled
  336.             ; by the EGA card. If not, it needs to be
  337.     mov    dx,3c2h ; handled by another routine in the vector
  338.     in    al,dx    ; chain. The PC AT in particular uses
  339.     test    al,80h    ; IRQ2 for multiple devices.
  340.     jz    use_old_vector
  341. endif
  342.     inc    cs:[vert_int_modulo_count]     ;count vert interrupts
  343.     sti                       ;enable interrupts
  344.     cmp    cs:[need_to_draw_something_flag],true ;anything to do?
  345.     je    process_queue               ; jmp if there is
  346.                            ; otherwise do nothing
  347. if ega
  348.     cli
  349.     mov    al,20h    ;issue a non_specific EOI (End Of Interrupt)
  350.     out    20h,al    ; so that interrupt controller chip will
  351.             ; acknowledge future vertical interrupts
  352.     mov    dx,cs:[crtc_base_address] ;re-enable ega card interrupt
  353.     mov    al,11h    ; select vertical retrace end
  354.     out    dx,al    ; register and clear vertical interrupt
  355.     mov    al,04h    ;
  356.     inc    dx    ;
  357.     out    dx,al    ;
  358.     mov    al,14h    ; then enable vertical interrupt
  359.     out    dx,al    ;
  360. endif
  361.     pop    ax    ;restore original values
  362.     pop    dx    ;
  363.     iret
  364. ;
  365. skip_this_object:
  366.     add    si,queue_item_length         ;point SI to next item
  367.     cmp    si,offset end_of_queue         ;see if we are done
  368.     je    draw                 ; jmp to draw if we are
  369.     jmp    get_next_objects_screen_adr  ; if not, erase next
  370. ;
  371. process_queue:
  372.     push    bx    ;save the rest of the world
  373.     push    cx    ;
  374.     push    bp    ;
  375.     push    si    ;
  376.     push    di    ;
  377.     push    ds    ;
  378.     push    es    ;
  379. ;
  380.     push    cs    ;setup environment
  381.     pop    ds    ; data is in code segment
  382.     cld        ; we will count up
  383.     mov    ax,screen_buffer_paragraph_adr
  384.     mov    es,ax    ; ES points to screen memory
  385. ;
  386.     mov    si,offset queue ;point to beginning of queue
  387. ;
  388. ;Erase all the active objects which have old screen positions
  389. ; different from their present screen position or have different
  390. ; image offsets
  391. ;
  392. get_next_objects_screen_adr:
  393.     mov    ax,[si+erase_screen_offset-draw_screen_offset]
  394.                   ; get the screen buffer
  395.                   ; offset of last draw
  396.     cmp    ax,0ffffh      ;if ffffh then object is
  397.     je    skip_this_object  ; yet to be drawn
  398.     cmp    ax,[si]       ;if new and old positions and
  399.     jne    erase_this_object ; images are same then skip erase
  400.     mov    di,[si+erase_image_offset-draw_screen_offset]
  401.     cmp    di,[si+draw_image_offset-draw_screen_offset]
  402.     je    skip_this_object  ;
  403. erase_this_object:
  404.     inc    si          ;point to next parameter
  405.     inc    si          ;
  406.     mov    di,ax          ;save screen buffer adr
  407.     lodsw              ;get distance to odd scan line
  408.     mov    bp,ax          ; save in BP for inline code use
  409.     lodsw              ;get distance to even scan line
  410.     mov    dx,ax          ; save in DX for inline code use
  411.     lodsw              ;get the width in words for erase
  412.     mov    cx,[si]       ;get address of erase inline code
  413. ;
  414.     push    si          ;save position so next object
  415.     push    ds          ; can be found
  416.     mov    ds,[background_segment] ;stuff to erase with
  417.     call    cx          ;erase it!
  418.     pop    ds          ;restore where
  419.     pop    si          ; we left off in queue
  420.     add    si,distance_from_entry_point_to_next_item ;next item
  421.     cmp    si,offset end_of_queue         ;see if we are done
  422.     jne    get_next_objects_screen_adr  ; jmp if more to erase
  423. ;
  424. ;Draw all the active objects by AND/ORing into screen buffer
  425. ;
  426. draw:
  427.     mov    si,offset queue   ;point to beginning of queue
  428. ;
  429. get_next_objects_screen_adr2:
  430.     lodsw              ;get screen buffer offset
  431.     mov    [si+erase_screen_offset-draw_screen_offset-2],ax
  432.                   ;save what will be old position
  433.     mov    di,[si+draw_image_offset-draw_screen_offset-2]
  434.                   ;save what will be old image offset
  435.     mov    [si+erase_image_offset-draw_screen_offset-2],di
  436.     cmp    ax,0ffffh      ;see if object is active
  437.     je    skip_this_object2 ; jmp if it isn't
  438.     mov    di,ax          ;save screen buffer adr
  439.     lodsw              ;get distance to odd scan line
  440.     mov    bp,ax          ; save in BP for inline code use
  441.     lodsw              ;get distance to even scan line
  442.     mov    dx,ax          ; save in DX for inline code use
  443.     add    si,length_of_erase_parms ;skip the erase parameters
  444.     lodsw              ;get the draw inline row adr
  445.     mov    cx,ax          ; save in CX for inline use
  446.     lodsw              ;get the draw inline row adr
  447.     mov    bx,ax          ; save in BX for call to inline
  448.     lodsw              ;get draw_image offset
  449.     push    si          ;save pointer to next queue item
  450.     mov    si,ax          ;save draw image in SI
  451.     call    bx          ;draw it!
  452.     pop    si          ;restore where we left off in queue
  453.     cmp    si,offset end_of_queue         ;see if we are done
  454.     jne    get_next_objects_screen_adr2 ; jmp if more to erase
  455. ;
  456. finish_up:
  457. if ega
  458.     cli
  459.     mov    al,20h    ;issue a non_specific EOI (End Of Interrupt)
  460.     out    20h,al    ; so that interrupt controller chip will
  461.             ; acknowledge future vertical interrupts
  462.     mov    dx,cs:[crtc_base_address] ;re-enable interrupt
  463.     mov    al,11h    ; select vertical retrace end
  464.     out    dx,al    ;  register and clear vertical interrupt
  465.     mov    al,04h    ;
  466.     inc    dx    ;
  467.     out    dx,al    ;  then enable vertical interrupt
  468.     mov    al,14h    ;
  469.     out    dx,al    ;
  470. endif
  471.     pop    es    ;restore all registers
  472.     pop    ds    ;
  473.     pop    di    ;
  474.     pop    si    ;
  475.     pop    bp    ;
  476.     pop    cx    ;
  477.     pop    bx    ;
  478.     pop    ax    ;
  479.     pop    dx    ;
  480.     mov    cs:[need_to_draw_something_flag],false
  481.             ;indicate no reason to    draw again until the
  482.             ; queue is changed
  483.     iret        ;restore flags and contine where interrupted
  484. ;
  485. skip_this_object2:
  486.     add    si,(queue_item_length-2)     ;point SI to next item
  487.     cmp    si,offset end_of_queue         ;see if we are done
  488.     jne    get_next_objects_screen_adr2 ; jmp if not
  489.     jmp short finish_up             ; jmp if all finished
  490. put_objects_on_screen endp
  491. ;
  492. ;
  493. ;This is inline code for finding the screen address for each line
  494. ; of the image and calling the AND-OR inline code.
  495. ;
  496. rlabel     macro     xx    ;this macro is used to label the inline code
  497. rline&xx&:        ; entry points
  498.     endm
  499. ;
  500. ;
  501. ; inline code for rows
  502. ;
  503. xx=42            ;there will be an entry point for each even
  504.             ; number of lines between 2 and 40. They will
  505.             ; be labeled "rline2", "rline4", ... "rline40"
  506.     rept    20    ;each repeat handles two lines
  507. xx=xx-2         ;calculate number of lines for entry point
  508.     rlabel    %xx    ;put in label for entry point
  509.  
  510.     call    cx    ;CX holds address of inline columns code
  511.     add    di,bp    ;calculate the address to start next line
  512.     call    cx    ;process image for odd scan line
  513.     sub    di,dx    ;calculate the address to start next line
  514.     endm        ; the next line will be an even line
  515.     ret
  516. ;
  517. ;Inline code for AND-ORing a line of the image into the screen
  518. ;
  519. clabel     macro    xx    ;this macro is used to label the inline code
  520. cline&xx&:        ; entry points for number of columns to AND-OR
  521.     endm        ;
  522. ;
  523. xx=10            ;this code can handle an image up to ten words
  524.     rept    10    ; wide
  525.     clabel    %xx    ;put in label for entry based on number of
  526.             ; words in a column
  527.     lodsw           ;get mask word
  528.     and    ax,es:[di] ;mask out background
  529.     or    ax,[si]    ;insert data word
  530.     inc    si       ;point to next mask word
  531.     inc    si       ;
  532.     stosw           ;return modified word to memory
  533. xx=xx-1            ;adjust label number
  534.     endm
  535.     ret           ;this return is executed at the end of every
  536.                ; line
  537. ;
  538. ;This table is used as an indirect address for jumping into
  539. ; the inline code for image moving.
  540. ;
  541. row_inline_vector_table label word ;there is no entry point for zero
  542.                    ; lines. Starting at 2 eliminates
  543.                    ; the need to store a dummy entry
  544.                    ; point address
  545. row_entry_address   macro   xx       ;this macro is used to generate
  546.         dw    rline&xx&  ; the labels corresponding to the
  547.         endm           ; inline code entry points
  548. ;
  549. xx=2
  550.     rept    20
  551.     row_entry_address    %xx
  552. xx=xx+2
  553.     endm
  554. ;
  555. ;This table is used as an indirect address for jumping into
  556. ; the inline code for exclusive-ORing columns.
  557. ;
  558. column_inline_vector_table label word ;there is no entry point for zero
  559.                       ; lines. Starting at 2 eliminates
  560.                       ; the need to store a dummy entry
  561.                       ; point address
  562. column_entry_address   macro   xx     ;this macro is used to generate
  563.          dw     cline&xx&    ; the labels corresponding to the
  564.          endm             ; inline code entry points
  565. ;
  566. xx=1
  567.     rept    10
  568.     column_entry_address   %xx
  569. xx=xx+1
  570.     endm
  571. ;
  572. ;This is inline code for erasing the image by restoring the screen
  573. ; memory map from the background buffer.
  574. ;
  575. elabel    macro    xx    ;this macro is used to label the inline code
  576. eline&xx&:        ; entry points
  577.     endm
  578. ;
  579. xx=42            ;there will be an entry point for each even
  580.             ; number of lines between 2 and 40. They will
  581.             ; be labeled "eline2", "eline4", ... "eline40"
  582.     rept    20
  583. xx=xx-2         ;calculate number of lines for this entry point
  584.     elabel  %xx     ;put in label for entry point
  585.     mov     si,di   ;erase using same offset in background buffer
  586.     mov     cx,ax   ;put width of image in words in CX to prepare for
  587.     rep     movsw   ; repeated move string on even line
  588.     add     di,bp   ;calculate address of next line DI + (2000h-width)
  589.     mov     si,di   ;erase using same offset in background buffer
  590.     mov     cx,ax   ;put width of image in bytes in CX to prepare for
  591.     rep     movsw   ; repeated move string on odd line
  592.     sub     di,dx   ;calculate address of next line DI - (1fb0h+width)
  593.     endm
  594.     ret
  595. ;
  596. ;This table is used as an indirect address for jumping into
  597. ; the inline code for erasing an image.
  598. ;
  599. erase_inline_vector_table label word ;there is no entry point for zero
  600.                      ; lines. Starting at 2 eliminates
  601.                      ; the need to store a dummy entry
  602.                      ; point address
  603. entry_address    macro    xx         ;this macro is used to generate
  604.         dw    eline&xx&    ; the labels corresponding to the
  605.         endm             ; inline code entry points
  606. ;
  607. xx=2
  608.     rept    20
  609.     entry_address    %xx
  610. xx=xx+2
  611.     endm
  612. ;
  613. cseg    ends
  614.     end
  615.